#ifndef _LISTE
#define _LISTE

// Inclusion des modules utilises par le module Liste
// (A l'exclusion de ceux qui sont seulement utilises dans l'implantation :
//  ceux la sont inclus dans le fichier d'implantation)

#include "element_generique.hpp" //offrant le type Elem

typedef void* Elem;

struct Cellule {
    Elem info;
    Cellule *suivant;
    Cellule *precedent;
};

struct Liste {
    Cellule *ad;
    void (*init)(Elem&, Elem, bool);
    void (*affectation)(Elem&, Elem);
    void (*affiche)(const Elem&);
    int (*compare)(const Elem&, const Elem&);
    void (*testament)(Elem&);
    int nb_elem;
};

void initListe(Liste & l, void (*fInit)(Elem&, Elem, bool), void(*fAffectation)(Elem&, Elem),
        void (*fAffiche)(const Elem&), int (*fCompare)(const Elem&, const Elem&),
        void (*fTestament)(Elem&));
//Precondition : l non prealablement initListee
//Postcondition : la liste l initListee est vide

void initListe(Liste & l1, const Liste & l2, bool verbose = false);
//Precondition : l1 non prealablement initListee,
//               l2 prealablement initListee et manipulee uniquement
//               a travers les operations du module
//Postcondition : la liste l1 initListee correspond à une copie de l2
// (mais les 2 listes sont totalement independantes l'une de l'autre)

void testamentListe(Liste & l, bool verbose = false);
//Precondition : l prealablement initListee et manipulee uniquement
//               a travers les operations du module
//Postcondition : l prete a etre detruite

void affectation(Liste & l1, const Liste & l2);
//Precondition : l1 et l2 prealablement initListees et manipulees uniquement
//               a travers les operations du module
//Postcondition : la liste l1 correspond à une copie de l2
// (mais les 2 listes sont totalement independantes l'une de l'autre)

void concat(Liste &l1, const Liste &l2, bool verbose = false);
//Precondition : l1 et l2 prealablement initListees et manipulees uniquement
//               a travers les operations du module
//Postcondition : les éléments de la laiste l2 sont ajoutés à la suite de la liste l1
// (mais les 2 listes sont totalement independantes l'une de l'autre)

bool testListeVide(const Liste & l);
//Precondition : l prealablement initListee et manipulee uniquement
//               a travers les operations du module
//Resultat : true si l est vide, false sinon

Elem premierElement(const Liste & l);
//Precondition : testListeVide(l)==false
//Resultat : valeur de l'Elem contenu dans la 1ere Cellule

Cellule * premiereCellule(const Liste & l);
//Precondition : l initListee et manipulee uniquement a travers les
//                operations du module
//Resultat : adresse de la premiere cellule de l si testListeVide(l)==false
//           NULL sinon
//           Attention : la liste l pourra ensuite etre modifiee a travers
//           la connaissance de l'adresse de sa premiere cellule

Cellule * derniereCellule(const Liste & l);

Cellule * celluleSuivante(const Cellule *c);

Cellule * celluleSuivante(const Cellule *c, const Liste & l);
//Precondition : c adresse valide d'une Cellule de la Liste l
//Resultat : adresse de la cellule suivante si elle existe
//           NULL sinon
//           Attention : la liste l pourra ensuite etre modifiee a travers
//           la connaissance de l'adresse d'une de ses cellules

Cellule * cellulePrecedente(const Cellule *c);

Cellule * cellulePrecedente(const Cellule *c, const Liste &l);

Elem elementCellule(const Cellule * c);
//Precondition : c adresse valide d'une Cellule d'une Liste
//Resultat : valeur de l'Elem contenu dans la Cellule

void affichageListe(const Liste & l, bool complet = false);
//Precondition : l initListee et manipulee uniquement a travers les
//                operations du module
//				 complet permet d'afficher une version plus complete de la liste
//Postcondition : Affichage exhaustif de tous les elements de l

void ajoutEnTete(const Elem & e, Liste & l, bool verbose = false);
//Precondition : l et e initListes et manipules uniquement a travers les
//                operations de leurs modules respectifs)
//Postcondition : L'Elem e est ajoute en tete de l

void suppressionEnTete(Liste & l, bool verbose = false);
//Precondition : testListeVide(l)==false
//Postcondition : la liste l perd son premier element

Cellule* rechercherElem(Liste &l, const Elem &e, bool verbose = false);
/* précond  :   l initialisé, e initialisé et contient la valeur à rechercher
 * postcond :   renvoie l'adresse de la première cellule de la liste qui contient l'élement recherché,
 *              ou NULL si l'élement n'a pas été trouvé
 */

void suppressionCellule(Liste &l, Cellule *c, bool verbose = false);
/* précond  :   l initialisé, c contient l'adresse d'une cellule de la liste
 * postcond :   supprime la cellule passer en paramètre de la liste
 */

void videListe(Liste & l, bool verbose = false);
//Precondition : aucune
//               (l initListee et manipulee uniquement a travers les
//                operations du module)
//Postcondition : testlisteVide(l)==true

void ajoutEnQueue(const Elem & e, Liste & l, bool verbose = false);
//Precondition : l et e initListes et manipules uniquement a travers les
//                operations de leurs modules respectifs
//Precondition : L'Elem e est ajoute en fin de la liste l

void triPartition(const Liste &l, Liste &result);
// bla bla

void separe(const Liste &l, Liste &inf, Liste &pivot, Liste &sup, bool verbose = false);
// bla bla bla

#endif
